package listnode

/**
两两交换链表中的节点
给你一个链表，两两交换其中相邻的节点，并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题（即，只能进行节点交换）。
输入：head = [1,2,3,4]
输出：[2,1,4,3]
*/
func swapPairs(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return head
	} else {
		//交换
		newHead := head.Next
		head.Next = swapPairs(newHead.Next)
		newHead.Next = head
		return newHead
	}
}

/**
K 个一组翻转链表
给你链表的头节点 head ，每 k 个节点一组进行翻转，请你返回修改后的链表。

k 是一个正整数，它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍，那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值，而是需要实际进行节点交换。
输入：head = [1,2,3,4,5], k = 2
输出：[2,1,4,3,5]
*/

func ReverseKGroup(head *ListNode, k int) *ListNode {
	//遍历整个链表，根据k值对节点分组（得到 head-tail 节点）然后对一个group中的node进行翻转
	var innerReverse func(a, b *ListNode) (*ListNode, *ListNode)
	innerReverse = func(head, tail *ListNode) (*ListNode, *ListNode) {
		//1->2->3->4
		//反转 要使用头插法才行
		//反转 段内链表  选定4为标记为，把头部的node 使用头插法 插入到 标记为node前 实现反转
		p := head
		flag := tail.Next //头插法定位节点,查到该节点之前
		for flag != tail {
			newHead := p.Next
			p.Next = flag
			flag = p
			p = newHead
		}
		return tail, head
	}
	//对链表尽心分组反转
	header := &ListNode{Next: head}
	pre := header //用于记录 上次组结尾的tail节点
	for head != nil {
		tail := pre
		for i := 0; i < k; i++ {
			tail = tail.Next
			if tail == nil {
				//剩下的不满足k个为一组 不进行反转了
				return header.Next
			}
		}
		newHead, newTail := innerReverse(head, tail)
		//把反转后的这组 链表 连起来
		pre.Next = newHead
		pre = newTail
		head = newTail.Next //更新为下一组的头节点
	}

	return header.Next
}
